import Taro from "@tarojs/taro";
import NIM from "../../libs/NIM_Web_NIM_v5.5.0";
import { envConfig } from "../config/index";
import logReport from "../request/logReport";
import { get, post } from "../request/request";
import apiUrl from "../urls";
import { initStartTime, showTimer } from "./time.config";
import { showToast } from "../tools/public";
import key from "../storageKeyMap";
import { getStoreData } from "../init";
import { addRelationship } from "../../service/data";

const IMappKey = envConfig.IMappKey;
let nim;
let offlineMsgList = {}; // 离线消息
const resetmsgs = {};
let custom = {};
let currentChatCardId = "";
let isIMLogin = false;
let getHistoryTimer;
let invalidCardList = [];

// 添加好友关系
function IMAddFriend(cardId, options) {
  const sourceType = +options.sourceType;

  const formData = {
    cardId,
    sourceType: sourceType || 2,
  };

  // 用户转发 和 名片海报 需要提供分享人的ID
  if (sourceType === 1 || sourceType === 4) {
    formData.forwardUserId = options.forwardUserId;
  }

  if (sourceType === 7 || sourceType === 14) {
    formData.jumpCardId = options.jumpCardId;
  }

  if (options.introductionId) {
    formData.introductionId = options.introductionId;
  }
  addRelationship(formData)
    .then((res) => {
      logReport({ content: { res, msg: "建立用户关系成功" }, type: 7 });
    })
    .catch((error) => {
      logReport({ content: { error, msg: "建立用户关系异常" }, type: 7 });
    });
}

// 获取已删除好友的列表，删除未读消息脏数据
function getInvalidCardList() {
  key.USERINFO_KEY;
  const formData = {
    userId: Taro.getStorageSync(key.USERINFO_KEY).userId,
    pageNum: 1,
    pageSize: 1000,
  };

  post(apiUrl.getInvalidCardList, formData, { silentFail: true })
    .then((res) => {
      invalidCardList = res || [];

      if (invalidCardList.length && Object.keys(offlineMsgList).length) {
        invalidCardList.forEach((item) => {
          if (offlineMsgList[item]) {
            resetNoRead(item);
          }
        });

        invalidCardList = [];

        offlineMsg && offlineMsg(offlineMsgList);
        offlineMsgHeader && offlineMsgHeader(offlineMsgList);
      }
    })
    .catch((res) => {
      console.log(res);
    });
}
// 创建用户IM账号
function createIMUser() {
  return new Promise((resolve, reject) => {
    const u = getStoreData("userInfo");
    const { __userInfo } = u;
    const { userId } = __userInfo;
    // 新用户注册
    get(
      apiUrl.createIMuserUrl,
      { endpoint: "Applet", userId },
      { silentFail: true }
    )
      .then((res) => {
        const IMToken = res;
        Taro.setStorageSync(key.IMTOKEN, IMToken);
        IMlogin(__userInfo, IMToken);
        upDateUserIMInfo(__userInfo);
        Taro.setStorageSync("isCreateImAccount", true);
        resolveIMAccountWaitQueue();
        resolve(res);
      })
      .catch(() => {
        // 刷新token
        post(apiUrl.updateIMToken, { userId }, { silentFail: true })
          .then((res) => {
            const IMToken = res;
            Taro.setStorageSync(key.IMTOKEN, IMToken);
            IMlogin(__userInfo, IMToken);
            upDateUserIMInfo(__userInfo);
            Taro.setStorageSync("isCreateImAccount", true);
            resolveIMAccountWaitQueue();
            resolve(res);
          })
          .catch((error) => reject(error));
      });
  });
}

function checkIMAccountCreated() {
  const isCreateImAccount = Taro.getStorageSync("isCreateImAccount");
  return !!isCreateImAccount;
}

const IMAccountWaitQueue = [];
function listenIMAccountStatus() {
  return new Promise((resolve, reject) => {
    if (checkIMAccountCreated()) {
      resolve();
      return;
    }

    logReport({ content: "加入创建IM账户回调队列", type: 7 });
    IMAccountWaitQueue.push(() => resolve());
  });
}

function resolveIMAccountWaitQueue() {
  logReport({ content: "执行创建IM账户回调队列成功", type: 7 });
  IMAccountWaitQueue.forEach((r) => r());
}

// 更新用户信息
function upDateUserIMInfo({ userId, avatarUrl, nickName }) {
  const formData = {
    avatar: avatarUrl,
    nickname: nickName,
    userId,
  };
  post(apiUrl.updateIMUserLogo, formData, { silentFail: true })
    .then(() => {})
    .catch(() => {});
}

// im登录
function IMlogin(userInfo, token) {
  const { avatarUrl, nickName, userId } = userInfo;

  custom = {
    endpoint: "Applet",
    avatar: avatarUrl,
    nickname: nickName,
    companyId: envConfig.companyId,
  };

  nim = NIM.getInstance({
    // debug: true,
    appKey: IMappKey,
    account: userId,
    autoMarkRead: false,
    token: token,
    onconnect: onConnect, // 连接成功
    onwillreconnect: onWillReconnect, // 即将重连
    ondisconnect: onDisconnect, // 丢失连接
    onerror: () => {}, // 错误
    onroamingmsgs: onRoamingMsgs, // 收到漫游消息
    onofflinemsgs: onOfflineMsgs, // 收到离线消息
    onmsg: onMsg, // 收到消息
  });
  
}

// 连接成功
function onConnect() {
  // console.log('IM连接成功')
  isIMLogin = true; // 登录成功
}

// 即将重连
function onWillReconnect() {
  // 此时说明 SDK 已经断开连接, 请开发者在界面上提示用户连接已断开, 而且正在重新建立连接
  // console.log('IM即将重连')
  isIMLogin = false; // 登录失败
}

// 丢失连接
function onDisconnect(error) {
  // 此时说明 SDK 处于断开状态, 开发者此时应该根据错误码提示相应的错误信息, 并且跳转到登录页面
  // console.log('IM丢失连接')
  isIMLogin = false; // 登录失败
  if (error) {
    // console.log(error)
    switch (error.code) {
      // 账号或者密码错误, 请跳转到登录页面并提示错误
      case 302:
        logReport({ content: error, type: 8 });
        // showToast('IM连接失败(302)')
        break;

      // 重复登录, 已经在其它端登录了, 请跳转到登录页面并提示错误
      case 417:
        logReport({ content: error, type: 8 });
        showToast("IM连接失败(417)");
        break;

      // 被踢, 请提示错误后跳转到登录页面
      case "kicked":
        logReport({ content: error, type: 8 });
        showToast("IM连接失败(-1)");
        break;

      default:
        // createIMUser()
        break;
    }
  }
}

// 收到漫游消息
function onRoamingMsgs() {
  // console.log('漫游消息 onRoamingMsgs', obj)
}

// 离线消息
function onOfflineMsgs(obj) {
  // console.log('离线消息 onOfflineMsgs', obj)
  const msgs = obj.msgs;
  const from = msgs[0].from;

  resetmsgs[from] = msgs;

  if (!offlineMsgList) {
    offlineMsgList = {};
  }

  offlineMsgList[from] = formatMsg(msgs);

  if (invalidCardList.length) {
    invalidCardList.forEach((item) => resetNoRead(item));
    invalidCardList = [];
  }

  offlineMsg && offlineMsg(offlineMsgList);
  offlineMsgHeader && offlineMsgHeader(offlineMsgList);
}

// 收到新消息
function onMsg(msg) {
  console.log("新消息 onMsg", msg);
  const obj = formatMsg(msg);
  const from = obj.from;
  const friendList = Taro.getStorageSync(key.CARDFRIENDLIST) || [];
  const currentMsgFrom =
    friendList.filter((item) => item.cardId === from)[0] || [];

  if (currentMsgFrom.length && +currentMsgFrom.shield === 1) return;

  if (offlineMsgList) {
    if (!offlineMsgList[from]) {
      offlineMsgList[from] = [];
    }

    offlineMsgList[from].push(obj);
  }

  newMsgListen && newMsgListen(obj, msg);
  setHeaderMsgList && setHeaderMsgList();
  // msgSubject.next(obj)
}

// 格式消息类型显示
function formatMsgType(content, type) {
  switch (type) {
    case 3:
      if (content.body && content.body.type === "product") return "【产品】";
      if (content.body && content.body.type === "mall") return "【商品】";
      break;

    case 4:
      return ((content.body && content.body.msg) || "").trim();

    case 5:
      return "【优惠券】";

    case 6:
      return "【表单】";
    case 7:
      return "【企业宣传册】";
  }

  return "【未知消息类型】";
}

// 格式化消息
function formatMsg(msgs) {
  const isGroup = Array.isArray(msgs);
  const results = (isGroup ? msgs : [msgs]).map((msg) => {
    const { type, from, text, time, flow, idClient, tip } = msg;
    const showtime = showTimer(time);
    const result = { from, type, time, flow, idClient, showtime };

    switch (type) {
      case "text":
        return {
          ...result,
          text,
          previewContent: (text || "").trim(),
        };

      case "image":
        return {
          ...result,
          url: msg.file.url,
          w: msg.file.w,
          h: msg.file.h,
          previewContent: "[图片]",
        };

      case "custom":
        let content = {};
        let msgType = -1;

        try {
          content = JSON.parse(msg.content);
          msgType = +content.msgType;

          if (msgType === 4 && typeof content.body === "string") {
            content.body = JSON.parse(content.body);
          }
        } catch (e) {}

        return {
          ...result,
          content,
          previewContent: formatMsgType(content, msgType),
        };

      case "tip":
        return {
          ...result,
          tip,
          previewContent: tip,
        };
    }

    return {};
  });

  return isGroup ? results : results[0];
}

// 获取第一页历史消息
function getHistoryList(cardId) {
  return new Promise((resolve, reject) => {
    function getList() {
      if (isIMLogin) {
        initStartTime();
        nim.getHistoryMsgs({
          scene: "p2p",
          asc: true,
          to: cardId,
          limit: 15,
          done(error, obj) {
            if (error) {
              reject(new Error("获取历史消息失败"));
              return;
            }

            const msgs = obj.msgs;
            // console.log('历史消息', Date.now(), msgs)
            nim.markMsgRead(msgs);
            sendMsgDone(msgs[msgs.length - 1]);
            resolve(formatMsg(msgs));
          },
        });
        return;
      } else {
        // eslint-disable-next-line prefer-promise-reject-errors
        reject({ message: "名片用户未登录过小程序，Im注册失败" });
      }

      clearTimeout(getHistoryTimer);
      getHistoryTimer = setTimeout(getList, 1000);
    }

    getList();
  });
}

// 获取后面的历史消息
function getMoreHistory(cardId, time) {
  return new Promise((resolve, reject) => {
    initStartTime();
    nim.getHistoryMsgs({
      scene: "p2p",
      asc: true,
      to: cardId,
      endTime: time,
      limit: 15,
      done(error, obj) {
        if (error) {
          reject(new Error("获取历史消息失败"));
          return;
        }

        resolve(formatMsg(obj.msgs));
      },
    });
  });
}

// 发送文本消息
function sendTextMsg({ to = "", content = "" } = {}) {
  return new Promise((resolve, reject) => {
    nim.sendText({
      isPushable: true,
      scene: "p2p",
      to: to,
      text: content,
      custom: JSON.stringify(custom), // 来源小程序
      done(error, msg) {
        if (!error) {
          sendMsgDone(msg);
          resolve(msg);
        } else {
          // console.error(error)
          reject(error);
        }
      },
    });
  });
}

// 发送图片消息
function sendImgMsg({ to = "", url = "" } = {}) {
  return new Promise((resolve, reject) => {
    nim.sendFile({
      scene: "p2p",
      to: to,
      type: "image",
      wxFilePath: url,
      custom: JSON.stringify(custom), // 来源小程序
      beginupload() {
        // - 如果开发者传入 fileInput, 在此回调之前不能修改 fileInput
        // - 在此回调之后可以取消图片上传, 此回调会接收一个参数 `upload`, 调用 `upload.abort();` 来取消文件上传
      },
      uploadprogress() {
        // console.log('文件总大小: ' + obj.total + 'bytes')
        // console.log('已经上传的大小: ' + obj.loaded + 'bytes')
        // console.log('上传进度: ' + obj.percentage)
        // console.log('上传进度文本: ' + obj.percentageText)
      },
      uploaddone(error) {
        // console.error(error)
        // console.log('上传' + (!error ? '成功' : '失败'))

        if (error) {
          reject(error);
        }
      },
      beforesend() {
        // console.log('正在发送p2p image消息, id=' + msg.idClient)
      },
      done() {
        resolve(false);
      },
    });
  });
}

// 提醒消息
function sendTipMsg({ to = "", tip = "" } = {}) {
  return new Promise((resolve, reject) => {
    nim.sendTipMsg({
      isPushable: true,
      scene: "p2p",
      to: to,
      tip: tip,
      custom: JSON.stringify(custom),
      done(error, msg) {
        if (!error) {
          sendMsgDone(msg);
          resolve(msg);
        } else {
          console.error(error);
          reject(error);
        }
      },
    });
  });
}

// 已读消息
function sendMsgDone(lastMsg) {
  // TODO: 暂时判断条件，未知请求
  if (currentChatCardId) {
    post(apiUrl.refreshChatTime, { cardId: currentChatCardId })
      .then(() => {})
      .catch(() => {});
  }

  nim.sendMsgReceipt({
    msg: lastMsg,
    done: () => {},
  });
}

/**
 *
 * @param {name} 来源
 * @param {to} cardId
 * @param {context} 价格
 * @param {pro_img} 商品/产品图片
 * @param {bs_id} 商品/产品id
 * @param {pro_title} 商品/产品标题
 * @param {type} 区分商品/产品
 */
function sendProduct({
  name = "",
  to = "",
  context = 0,
  proImg = "",
  bsId = "",
  proTitle = "",
  type = "",
  success = null,
  fail = null,
} = {}) {
  const _content = {
    msgType: 3,
    body: {
      name,
      pro_title: proTitle,
      pro_img: proImg,
      bs_id: bsId,
      context,
      type,
    },
  };
  sendCustomMsg(to, _content, success, fail);
}

function sendCustomMsg(to, content, success, fail) {
  nim.sendCustomMsg({
    isPushable: true,
    scene: "p2p",
    to: to,
    custom: JSON.stringify(custom),
    content: JSON.stringify(content),
    done(error, msg) {
      if (!error) {
        success && success(msg);
      } else {
        fail && fail();
      }
    },
  });
}

function getOnOfflineMsgs() {
  const friendList = Taro.getStorageSync(key.CARDFRIENDLIST) || [];
  friendList.forEach((item) => {
    // 名片屏蔽所有消息清空
    if (+item.shield === 1) resetNoRead(item.cardId);
  });
  return offlineMsgList;
}

// 清空未读消息
function resetNoRead(cardId) {
  // 这里存在bug
  // nim 是异步拿到的 默认是undefined
  // 但是这里是同步操作
  // 导致客户端undefined is not an object 异常
  // 需要处理
  if (!nim) return;
  nim.markMsgRead(resetmsgs[cardId]);
  if (offlineMsgList && offlineMsgList[cardId]) {
    delete offlineMsgList[cardId];
  }
}

// 消息监听
// 离线消息监听
let offlineMsg = null;

function setOfflineMsgLister(fn) {
  offlineMsg = fn;
}

// 离线消息监听
let offlineMsgHeader = null;

function setOfflineMsgHeaderLister(fn) {
  offlineMsgHeader = fn;
}

// 新消息监听
let newMsgListen = null;

function setMsgListner(fn) {
  newMsgListen = fn;
}

// 停止新消息监听
function clearMsgListner() {
  newMsgListen = null;
}

// 新消息监听
let setHeaderMsgList = null;

function setHeaderMsgListfn(fn) {
  setHeaderMsgList = fn;
}

// 更改当前聊天账号
function changeChatCardId(id) {
  currentChatCardId = id;
}

function clearIMTimeout() {
  clearTimeout(getHistoryTimer);
}



const IMToken = Taro.getStorageSync(key.IMTOKEN);
if (IMToken) {
  const userInfo = Taro.getStorageSync(key.USERINFO_KEY);
  IMlogin(userInfo, IMToken);
}

export {
  getInvalidCardList,
  sendTextMsg, // 发送消息
  sendImgMsg, // 发送文件信息
  sendTipMsg, // 发送提示消息
  sendCustomMsg, // 发送定制消息
  sendProduct, // 发送产品
  sendMsgDone, // 消息已读
  listenIMAccountStatus,
  getHistoryList, // 拉取历史消息
  getMoreHistory,
  setMsgListner, // 收到新消息回调
  resetNoRead,
  setOfflineMsgLister, // 监听离线消息显示
  getOnOfflineMsgs,
  clearMsgListner,
  changeChatCardId,
  setHeaderMsgListfn,
  setOfflineMsgHeaderLister,
  clearIMTimeout,
  createIMUser,
  IMAddFriend,
};
